package com.kx.smartdevice.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kx.smartdevice.event.ColorEvent;
import com.kx.smartdevice.event.DeviceStatusEvent;
import com.kx.smartdevice.event.DeviceStatusType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 控制灯开关的WebSocket
 *
 * @ClassName PowerCommandWebSocket
 * @Author Sun
 * @Date 2021/6/2 11:41
 */
@Component
public class ColorCommandWebSocket extends TextWebSocketHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ApplicationContext context;

    //保存设备会话的map
    private ConcurrentReferenceHashMap<String, WebSocketSession> allClients = new ConcurrentReferenceHashMap<>();

    //保存设备最后的会话时间
    private ConcurrentHashMap<String, Long> updateTimes = new ConcurrentHashMap();

    /**
     * 设备和 websocket 建立连接之后
     *
     * @param session 存储建立连接的会话
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //获取每个设备的唯一标识
        String uuid = (String) session.getAttributes().get("uuid");
        System.err.println("设备和颜色控制器建立连接了" + uuid);
        //保存当前会话,在保存前要先看看之前有没有会话,有的话说明是重复连接,需要关闭
        WebSocketSession socketSession = allClients.get(uuid);
        //先替换在移除
        allClients.put(uuid, socketSession);

        //更新状态,需要设备的 service,可以发送事件
        context.publishEvent(new DeviceStatusEvent(uuid, DeviceStatusType.OPEN));//将设备设置为在线状态
        //保存设备最后的会话时间
        updateTimes.put(uuid, System.currentTimeMillis());
        if (socketSession != null && socketSession.isOpen()) {
            socketSession.close();
        }

    }

    /**
     * 处理设备发过来的文本内容
     *
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        try {
            Map map = objectMapper.readValue(message.getPayload(), Map.class);
            String uuid = (String) map.get("toUser");
            String command = (String) map.get("msg");
            WebSocketSession socketSession = allClients.get(uuid);
            if (socketSession != null&&socketSession.isOpen()) {
                socketSession.sendMessage(new TextMessage(command));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        super.handleTransportError(session, exception);
    }

    /**
     * 连接关闭之后
     *
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String uuid = (String) session.getAttributes().get("uuid");
        //先将设备移除
        allClients.remove(uuid);
        //更新设备状态信息,需要设备的 service,可以发送事件
        context.publishEvent(new DeviceStatusEvent(uuid, DeviceStatusType.CLOSE));//将设备设置为离线状态
    }

    @EventListener
    public void OnEvent(ColorEvent event) {
        String uuid = event.getUuid();
        String command = event.getCommand();

        //根据设备id找到设备的会话
        WebSocketSession socketSession = allClients.get(uuid);
        if (socketSession != null && socketSession.isOpen()) {
            try {
                //发送指令
                socketSession.sendMessage(new TextMessage(command));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
